#!/usr/bin/python

import time
from threading import Thread
import sys, time
from wx.lib.stattext import GenStaticText
import wx, urllib
from wxPython.wx import wxMenu, wxMenuBar, wxNewId, wxPasswordEntryDialog
from loginDialog import LoginDialog
import datetime, random
from ritzWin import Browser
import config as c
import playersInfo as pi

LOGIN_ID = wxNewId()
ID_FILE_EXIT = wxNewId()
SAVE_SETTINGS_ID = wxNewId()

def getTimestamp():
  return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

class MyFrame(wx.Frame):
  def __init__(self, parent, id, title, testMode):
    def initSelf():
      wx.Frame.__init__(self, parent, id, title, size=(850, 570))
    initSelf()

    def createFileMenu():
      file_menu = wxMenu()
      file_menu.Append(LOGIN_ID, 'Login')
      file_menu.Append(SAVE_SETTINGS_ID, 'Save Config')
      file_menu.AppendSeparator()
      file_menu.Append(ID_FILE_EXIT, 'Exit Program')
      menu_bar = wxMenuBar()
      menu_bar.Append(file_menu, 'File')
      self.SetMenuBar(menu_bar)
      wx.EVT_MENU(self, ID_FILE_EXIT, self.close)
      wx.EVT_MENU(self, LOGIN_ID, self.doLoginDialog)
      wx.EVT_MENU(self, SAVE_SETTINGS_ID, self.saveSettings)

    def createKeyboardShortcuts():
      accel_tbl = wx.AcceleratorTable([
            (wx.ACCEL_CTRL, ord('Q'), ID_FILE_EXIT ), 
            (wx.ACCEL_CTRL, ord('S'), SAVE_SETTINGS_ID ), 
            (wx.ACCEL_CTRL, ord('L'), LOGIN_ID)])
      self.SetAcceleratorTable(accel_tbl)

    def createListArea():
      self.execListBox = wx.ListCtrl(panel, -1, style=wx.LC_REPORT|wx.BORDER_SUNKEN, size=(150,470))
      self.notExecListBox = wx.ListCtrl(panel, -1, style=wx.LC_REPORT|wx.BORDER_SUNKEN, size=(150,500) )
      self.execListBox.InsertColumn(0, "Daily")
      self.execListBox.InsertColumn(1, "Last Attempt")
      self.notExecListBox.InsertColumn(0, "Daily")
      self.notExecListBox.InsertColumn(1, "Last Attempt")
      for index, row in enumerate(c.execChoices):
        self.execListBox.InsertStringItem(index, row)
        self.notExecListBox.SetStringItem(index, 1, '')
      for index, row in enumerate(c.notExecChoices):
        self.notExecListBox.InsertStringItem(index, row)
        self.notExecListBox.SetStringItem(index, 1, '')
      self.startButton = wx.Button(panel, 1, 'Start')
      self.moveRightButton = wx.Button(panel, 14, '>', size=(35,35))
      self.moveLeftButton  = wx.Button(panel, 15, '<', size=(35,35))

      listArea = wx.BoxSizer(wx.HORIZONTAL)
      execListCol = wx.BoxSizer(wx.VERTICAL)
      execListCol.Add(self.execListBox, border=1)
      execListCol.Add(self.startButton,border = 10, flag=wx.CENTER)
      listArea.Add(execListCol, border=10)
      listButtons = wx.BoxSizer(wx.VERTICAL)
      listButtons.Add(self.moveRightButton, flag=wx.CENTER, border=10)
      listButtons.Add(self.moveLeftButton, flag=wx.CENTER, border=10)
      listArea.Add(listButtons,border = 10, flag=wx.CENTER)
      listArea.Add(self.notExecListBox, border=1)
      return listArea

    def createLogArea():
      innerVbox2 = wx.BoxSizer(wx.VERTICAL)

      self.rewardBox = wx.TextCtrl(panel, 10, "[%s] Rewards so far:" % (getTimestamp()), size=(500,200), style = wx.TE_MULTILINE|wx.TE_READONLY)
      self.logBox = wx.TextCtrl(panel, 10, "[%s] Started Ritzwin's Daily Doer" % (getTimestamp()), size=(500,200), style = wx.TE_MULTILINE|wx.TE_READONLY)
      pageTimesRow = wx.BoxSizer(wx.HORIZONTAL)
      staticTextCol = wx.BoxSizer(wx.VERTICAL)
      textCtrlCol = wx.BoxSizer(wx.VERTICAL)
      staticTextCol.Add(wx.StaticText(panel, -1, 'Page Min', size=(150,25)))
      staticTextCol.Add(wx.StaticText(panel, -1, 'Page Max', size=(150,25)))
      staticTextCol.Add(wx.StaticText(panel, -1, 'Between Dailies Min', size=(150,25)))
      staticTextCol.Add(wx.StaticText(panel, -1, 'Between Dailies Max', size=(150,25)))

      self.pageMin = wx.TextCtrl(panel, 10, c.pageMin, size=(60,25))
      self.pageMax = wx.TextCtrl(panel, 10, c.pageMax, size=(60,25))
      self.dailyMin = wx.TextCtrl(panel, 10, c.betweenDailiesMin, size=(60,25))
      self.dailyMax = wx.TextCtrl(panel, 10, c.betweenDailiesMax, size=(60,25))

      textCtrlCol.Add(self.pageMin, border=10)
      textCtrlCol.Add(self.pageMax, border=10)
      textCtrlCol.Add(self.dailyMin, border=10)
      textCtrlCol.Add(self.dailyMax, border=10)


      pageTimesRow.Add(staticTextCol, border=10)
      pageTimesRow.Add(textCtrlCol, border=10)


      innerVbox2.Add(self.rewardBox, border=10)
      innerVbox2.Add(self.logBox, border=10)
      innerVbox2.Add(pageTimesRow, border=10)

      return innerVbox2


    with open('userAgent.txt','r') as f:
      self.userAgent = f.read().strip()
    self.br = Browser(self.userAgent, testMode)

    panel = wx.Panel(self)

    createFileMenu()
    createKeyboardShortcuts()

    panel.Centre()
    hbox = wx.BoxSizer(wx.VERTICAL)
    vbox = wx.BoxSizer(wx.HORIZONTAL)

    self.currentUser = None
    if testMode:
      playerLabel = 'TESTMODE'
      self.currentUser = 'TESTMODE'
    else:
      playerLabel = None
    self.playerNameBox = wx.StaticText(panel, -1, playerLabel or '')
    self.userAgentBox = wx.StaticText(panel, -1, "User-Agent: %s" % self.userAgent)

    vbox.Add(createListArea(), border=5)
    vbox.Add(createLogArea())

    hboxPlayer = wx.BoxSizer(wx.HORIZONTAL)
    vbox.Add((-1, 10))
    hboxPlayer.Add(wx.StaticText(panel, -1, 'Player: '), flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
    hboxPlayer.Add(self.playerNameBox, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
    hboxPlayer.Add((100, -1))
    hboxPlayer.Add(self.userAgentBox, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
    hbox.Add(hboxPlayer)
    hbox.Add(vbox)
    panel.SetSizer(hbox)
    self.Bind(wx.EVT_BUTTON, self.putInRight, id=14)
    self.Bind(wx.EVT_BUTTON, self.putInLeft, id=15)
    self.Bind(wx.EVT_BUTTON, self.start, id=1)

    self.startButton.SetFocus()
    EVT_RESULT(self, self.doResult)

    self.testMode = testMode
    self.worker = None
    self.updateTimes()


  def updateTimes(self):
    from playersInfo import players
    from formDailiesData import dailyData
    def updateFor(box):
      count = box.GetItemCount()
      user = self.currentUser or 'TESTMODE'
      for i in range(count):
        item = box.GetItemText(i)
        ts = players[user].get(item, 0)
        lastPlayed = datetime.datetime.fromtimestamp(ts)
        box.SetStringItem(i, 1, str(lastPlayed.strftime('%H:%M %d-%m')))
        box.SetItemFont(i, wx.Font(6, wx.SWISS, wx.NORMAL, wx.BOLD, False,'MS Shell Dlg 2'))
        box.SetItemBackgroundColour(i,(100,250,100))
        freq = dailyData[str(item)]['freq']
        if freq == 'daily':
          sameDay = lastPlayed.strftime('%D') == datetime.datetime.fromtimestamp(int(time.time())).strftime('%D')
          if sameDay:
            box.SetItemBackgroundColour(i,(150,150,150))
        else:
          minuteDiff = (int(time.time()) - ts)/60
          if minuteDiff<int(freq):
            box.SetItemBackgroundColour(i,(250,200,0))

    updateFor(self.execListBox)
    updateFor(self.notExecListBox)


  def saveSettings(self, event):
    execChoices = [self.execListBox.GetItemText(index) for index in range(self.execListBox.GetItemCount())]
    notExecChoices = [self.notExecListBox.GetItemText(index) for index in range(self.notExecListBox.GetItemCount())]

    pageMin = self.pageMin.GetValue()
    pageMax = self.pageMax.GetValue()
    dailyMin = self.dailyMin.GetValue()
    dailyMax = self.dailyMax.GetValue()

    file  = ''
    file += "execChoices = %s\n\n" % str(execChoices)
    file += "notExecChoices = %s\n\n" % str(notExecChoices)
    file += "pageMin = '%s'\n" % pageMin
    file += "pageMax = '%s'\n" % pageMax
    file += "betweenDailiesMin = '%s'\n" % dailyMin
    file += "betweenDailiesMax = '%s'\n" % dailyMax
    with open('config.py','w') as f:
      f.write(file)


  def close(self, event):
    self.Close()
    self.Destroy()

  def doResult(self, event):
    data = eval(str(event.data))
    for item in data:
      if 'sleep' in data[item]:
        self.updateLogBox( 'Waiting for [%s] seconds.' % data[item]['sleep'] )
      if 'pageSleep' in data[item]:
        self.updateLogBox( 'Waiting before %s for [%s] seconds.' % (item, data[item]['pageSleep']) )
      if 'timeEst' in data[item]:
        self.updateLogBox( 'Estimated wait time for %s is [%s] seconds.' % (item, data[item]['timeEst']) )
      if 'reward' in data[item]:
        self.updateRewardBox( data[item]['reward'], item )
      if 'complete' in data[item]:
        self.worker = None
        self.startButton.SetLabel('Start')
      if 'stop' in data[item]:
        self.worker.abort()
        self.worker = None
        self.startButton.SetLabel('Start')
    self.updateTimes()


  def doSleep(self, seconds):
    if not self.testMode:
      time.sleep(seconds)


  def start(self, event):
    time.sleep(0.5)
    if self.worker:
      self.worker.abort()
      return

    self.startButton.SetLabel('Stop')
    itemsList = [self.execListBox.GetItemText(index) for index in range(self.execListBox.GetItemCount())]
    self.worker = WorkerThread(self, itemsList, self.br)


  def putInRight(self, event):
    self.swapListCtrlObjects( self.execListBox, self.notExecListBox )
    self.updateTimes()

  def putInLeft(self, event):
    self.swapListCtrlObjects( self.notExecListBox, self.execListBox )
    self.updateTimes()

  def swapListCtrlObjects(self, fromList, toList):
    selectedIndexes = [index for index in range(fromList.GetItemCount()) if fromList.IsSelected(index)]
    selectedIndexes.reverse()
    movingObjects = []
    for i in selectedIndexes:
      movingObjects.append( fromList.GetItemText(i) )
      fromList.DeleteItem(i)
    for i in movingObjects:
      toList.InsertStringItem(0,i)




  def doLoginDialog(self, event):
    dia = LoginDialog(None, 'Login / Create new user', '', pi.players, pi.lastLoadedPlayer)
    dia.ShowModal()
    loginInfo = dia.GetResult()
    if loginInfo[0] is not None:
      waitTime = self.getPageSleepTime()
      self.updateLogBox( 'Sleeping for [%s] seconds.' % waitTime )
      response = self.br.doLogin(loginInfo[0], loginInfo[1], waitTime)
      if response == 'Successful login':
        self.playerNameBox.SetLabel('%s' % loginInfo[0])
        self.playerNameBox.SetForegroundColour((0,255,0))
        self.currentUser = loginInfo[0]
      else:
        with open('logs/loginResp.html','w') as f:
          f.write(response)
        self.playerNameBox.SetLabel('Login Failed (bad password maybe?)')
        self.playerNameBox.SetForegroundColour((255,0,0))
      self.updateLogBox( response )
    dia.Destroy()
    self.updateTimes()


  def getBetweenDailysTime(self):
    return random.uniform( float(self.dailyMin.GetValue()), float(self.dailyMax.GetValue()) )


  def getPageSleepTime(self):
    return random.uniform( float(self.pageMin.GetValue()), float(self.pageMax.GetValue()) )


  def updateLogBox(self, newLine ):
    self.logBox.AppendText( '\n[%s] %s' % (getTimestamp(), newLine) + self.logBox.GetLabel() )


  def updateRewardBox(self, newLine, daily ):
    self.rewardBox.AppendText( self.rewardBox.GetLabel() + '\n' + '[%s] %s -> %s' % (getTimestamp(), daily, newLine) )




class WorkerThread(Thread):
  def __init__(self, notify_window, dailyToDo, br):
    Thread.__init__(self)
    self._notify_window = notify_window
    self._want_abort = 0
    self.dailyToDo = dailyToDo
    self.br = br
    self.start()


  def run(self):
    for item in self.dailyToDo:
      if self._want_abort:
        wx.PostEvent(self._notify_window, ResultEvent({'buttonEvent':{'stop':-1}}))
        return

      betweenGets = self._notify_window.getBetweenDailysTime()
      waitTime = self._notify_window.getPageSleepTime()
      wx.PostEvent(self._notify_window, ResultEvent({item:{'pageSleep':betweenGets}}))
      response = ''
      if not self._notify_window.testMode:
        time.sleep( betweenGets )
      wx.PostEvent(self._notify_window, ResultEvent({item:{'sleep': waitTime}}))
      if item == 'Tombola'              : response = self.br.getTombola( waitTime )
      elif item == 'Shrine'             : response = self.br.getShrine( waitTime )
      elif item == 'Slug'               : response = self.br.getSlug( waitTime )
      elif item == 'Omelette'           : response = self.br.getOmelette( waitTime )
      elif item == 'Anchor'             : response = self.br.getAnchor( waitTime )
      elif item == 'Bob4Apples'         : response = self.br.getBobApples( waitTime )
      elif item == 'Ice Scratch Card'   : response = self.br.getIceScratchCard( waitTime )
      elif item == 'Desert Scratch Card': response = self.br.getDesertScratchCard( waitTime )
      elif item == 'Halloween Scratch Card' : response = self.br.getHalloweenScratchCard( waitTime )
      elif item == 'Fruit Machine'      : response = self.br.getFruitMachine( waitTime )
      elif item == 'Plushie Of Prosperity' : response = self.br.getPlushieOfProsperity( waitTime )
      elif item == 'Fishing'            : response = self.br.getFishing( waitTime )
      elif item == 'Healing Springs'    : response = self.br.getHealingSprings( waitTime )
      elif item == '20x Bagatelle'      : 
        waitTimes = [self._notify_window.getPageSleepTime() for i in range(21)]
        wx.PostEvent(self._notify_window, ResultEvent({item:{'timeEst' : str(eval(''.join(["+%s" % wt for wt in waitTimes]))) }} ))
        response = self.br.getBagatelle( waitTime, waitTimes )
      elif item == 'Jelly'              : response = self.br.getJelly( waitTime )
      elif item == 'Wheel of Excitement': response = self.br.getWheelOfExcitement( waitTime )
      elif item == 'Bank Interest'      : response = self.br.getBankInterest( waitTime )
      elif item == 'Grumpy King'         : response = self.br.getGrumpyKing( waitTime )
      elif item == 'Potato Counter'     : response = self.br.getPotatoCounter( waitTime )
      wx.PostEvent(self._notify_window, ResultEvent({item:{'reward':response}}))
      storeLastVisit(self._notify_window.currentUser, item)

    wx.PostEvent(self._notify_window, ResultEvent({'buttonEvent':{'complete':-1}}))

  def abort(self):
    self._want_abort = 1

EVT_RESULT_ID = wx.NewId()


def storeLastVisit(player, daily):
  import playersInfo as pi
  pd = pi.players
  pd[player][daily] = int(time.time())
  file = "players = %s\n\nlastLoadedPlayer = '%s'" % (pd, player)
  with open('playersInfo.py', 'w') as f:
    f.write(file)


def EVT_RESULT(win, func):
  win.Connect(-1, -1, EVT_RESULT_ID, func)

class ResultEvent(wx.PyEvent):
  def __init__(self, data):
    wx.PyEvent.__init__(self)
    self.SetEventType(EVT_RESULT_ID)
    self.data = data


class DailyRow(object):

  def __init__(self, daily, lastPlayed):
    self.id = id(self)
    self.daily = daily
    self.lastPlayed = lastPlayed



class MyApp(wx.App):
  def OnInit(self):
    testFlag = True
    if len(sys.argv)>1 and sys.argv[1] == 'prod':
      testFlag = False
    self.frame = MyFrame(None, -1, "Ritzwin's Daily Doer", testFlag)
    self.frame.Show(True)
    self.frame.SetPosition(wx.Point(100,0))
    return True


if __name__ == '__main__':

  app = MyApp(0)
  app.MainLoop()
